/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include <dylab/utils/Console.h>

//===========================================================================================
#ifdef DYLAB_PLATFORM_WINDOWS
    #include <windows.h>

    static HWND _getHWND(DYLAB_CONSOLE_HANDLE handle, const char * title)
    {
	    if (handle == INVALID_HANDLE_VALUE) 
		    return NULL;

	    // try to find our console window and return its HWND
        return FindWindow("ConsoleWindowClass", title);
    }
#endif

//===========================================================================================
dylab::Console::Console(const String & title, bool showConsole, bool disableCloseButton, uint32_t color)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
	    // allocate a new console
	    if(!AllocConsole())
		    return;
    	
	    // create the console
	    mConsoleHandle = CreateFile("CONOUT$", GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
	    if (mConsoleHandle == INVALID_HANDLE_VALUE)
		    return;
    	
        // set console mode
	    if (SetConsoleMode(mConsoleHandle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT ) == 0)
		    return;
    	
        // show/hide the console
        show(showConsole);

        // disable close button
        if (disableCloseButton)
        {
        	HWND hWnd = _getHWND(mConsoleHandle, getTitle().c_str());
	
	        // disable the [x] button if we found our console
	        if (hWnd != NULL)
	        {
		        HMENU hMenu = GetSystemMenu(hWnd, 0);
		        if (hMenu != NULL)
		        {
			        DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
			        DrawMenuBar(hWnd);
		        }
	        }
        }

        // set console position
        setPosition(240, 630, 800, 340);

        // set console title
        setTitle(title);

        // set console color
        setColor(color);
    #endif
}
//-----------------------------------------------------------------------------
dylab::Console::~Console()
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return;

	    // free the console
	    FreeConsole();
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::setTitle(const String & title)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        SetConsoleTitle(title.c_str());
    #endif
}
//-----------------------------------------------------------------------------
dylab::String dylab::Console::getTitle()
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return "";

	    // get the title of our console and return it
	    char windowTitle[256] = "";
	    GetConsoleTitle(windowTitle, sizeof(windowTitle));
	    return windowTitle;
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::setColor(uint32_t color)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return;

	    if (color != 0) // change font and/or background color
		    SetConsoleTextAttribute(mConsoleHandle, static_cast<WORD>(color));	    
	    else // no color specified, reset to defaults (white font on black background)
		    SetConsoleTextAttribute(mConsoleHandle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); // white text on black bg
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::setPosition(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return;

	    // get out console's HWND and show/hide the console
	    HWND hWnd = _getHWND(mConsoleHandle, getTitle().c_str());
	    if(hWnd != NULL)
		    SetWindowPos(hWnd, NULL, x, y, width, height, SWP_NOZORDER);
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::show(bool show)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return;

	    // get out console's HWND and show/hide the console
	    HWND hWnd = _getHWND(mConsoleHandle, getTitle().c_str());
	    if(hWnd != NULL)
		    ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::clear()
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == NULL)
            return;

	    COORD coordScreen = { 0, 0 };

	    BOOL bSuccess;
        DWORD cCharsWritten;
        CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 
        DWORD dwConSize; 

	    /* get the number of character cells in the current buffer */ 
        bSuccess = GetConsoleScreenBufferInfo(mConsoleHandle, &csbi);
        if (!bSuccess) return;
        dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

        /* fill the entire screen with blanks */ 
        bSuccess = FillConsoleOutputCharacter(mConsoleHandle, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten);
        if (!bSuccess) return;

        /* get the current text attribute */ 
        bSuccess = GetConsoleScreenBufferInfo(mConsoleHandle, &csbi);
        if (!bSuccess) return;

        /* now set the buffer's attributes accordingly */ 
        bSuccess = FillConsoleOutputAttribute(mConsoleHandle, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
        if (!bSuccess) return;

        /* put the cursor at (0, 0) */ 
        bSuccess = SetConsoleCursorPosition(mConsoleHandle, coordScreen);
        if (!bSuccess) return;
    #endif
}
//-----------------------------------------------------------------------------
void dylab::Console::_output(const String & text)
{
    #ifdef DYLAB_PLATFORM_WINDOWS
        if (mConsoleHandle == INVALID_HANDLE_VALUE)
            return;

        // write to the console
        DWORD written;
        WriteConsole(mConsoleHandle, text.c_str(), static_cast<DWORD>(text.size()), &written, 0);
    #endif
}
//-----------------------------------------------------------------------------